package com.chj.design.sk;

import java.util.ArrayList;
import java.util.List;

// https://blog.csdn.net/pange1991/article/details/81184715
public class Code09_Visitor {

	/**
	 * 公司员工（被访问者）抽象类
	 *
	 */
	public static abstract class Employee {

		/**
		 * 接收/引用一个抽象访问者对象
		 * 
		 * @param department 抽象访问者 这里指的是公司部门如 人力资源部、财务部
		 */
		public abstract void accept(Department department);

	}

	/**
	 * 公司员工：管理者（具体的被访问者对象）
	 * 
	 */
	public static class ManagerEmployee extends Employee {
		// 员工姓名
		private String name;
		// 每天上班时长
		private int timeSheet;
		// 每月工资
		private double wage;
		// 请假/迟到 惩罚时长
		private int punishmentTime;

		public ManagerEmployee(String name, int timeSheet, double wage, int punishmentTime) {
			this.name = name;
			this.timeSheet = timeSheet;
			this.wage = wage;
			this.punishmentTime = punishmentTime;
		}

		@Override
		public void accept(Department department) {
			department.visit(this);
		}

		/**
		 * 获取每月的上班实际时长 = 每天上班时长 * 每月上班天数 - 惩罚时长
		 * 
		 * @return
		 */
		public int getTotalTimeSheet() {
			return timeSheet * 22 - punishmentTime;
		}

		/**
		 * 获取每月实际应发工资 = 每月固定工资 - 惩罚时长 * 5<br/>
		 * <作为公司管理者 每迟到1小时 扣5块钱>
		 * 
		 * @return
		 */
		public double getTotalWage() {
			return wage - punishmentTime * 5;
		}

		public String getName() {
			return name;
		}

		public void setName(String name) {
			this.name = name;
		}

		public double getWage() {
			return wage;
		}

		public void setWage(double wage) {
			this.wage = wage;
		}

		public int getPunishmentTime() {
			return punishmentTime;
		}

		public void setPunishmentTime(int punishmentTime) {
			this.punishmentTime = punishmentTime;
		}

	}

	/**
	 * 公司普通员工（具体的被访问者对象）
	 *
	 */
	public static class GeneralEmployee extends Employee {
		// 员工姓名
		private String name;
		// 每天上班时长
		private int timeSheet;
		// 每月工资
		private double wage;
		// 请假/迟到 惩罚时长
		private int punishmentTime;

		public GeneralEmployee(String name, int timeSheet, double wage, int punishmentTime) {
			this.name = name;
			this.timeSheet = timeSheet;
			this.wage = wage;
			this.punishmentTime = punishmentTime;
		}

		@Override
		public void accept(Department department) {
			department.visit(this);
		}

		/**
		 * 获取每月的上班实际时长 = 每天上班时长 * 每月上班天数 - 惩罚时长
		 * 
		 * @return
		 */
		public int getTotalTimeSheet() {
			return timeSheet * 22 - punishmentTime;
		}

		/**
		 * 获取每月实际应发工资 = 每月固定工资 - 惩罚时长 * 10<br/>
		 * <作为公司普通员工 每迟到1小时 扣10块钱 坑吧？ 哈哈>
		 * 
		 * @return
		 */
		public double getTotalWage() {
			return wage - punishmentTime * 10;
		}

		public String getName() {
			return name;
		}

		public void setName(String name) {
			this.name = name;
		}

		public double getWage() {
			return wage;
		}

		public void setWage(double wage) {
			this.wage = wage;
		}

		public int getPunishmentTime() {
			return punishmentTime;
		}

		public void setPunishmentTime(int punishmentTime) {
			this.punishmentTime = punishmentTime;
		}

	}

	/**
	 * 公司部门（访问者）抽象类
	 *
	 */
	public static abstract class Department {

		// 声明一组重载的访问方法，用于访问不同类型的具体元素（这里指的是不同的员工）

		/**
		 * 抽象方法 访问公司管理者对象<br/>
		 * 具体访问对象的什么 就由具体的访问者子类（这里指的是不同的具体部门）去实现
		 * 
		 * @param me
		 */
		public abstract void visit(ManagerEmployee me);

		/**
		 * 抽象方法 访问公司普通员工对象<br/>
		 * 具体访问对象的什么 就由具体的访问者子类（这里指的是不同的具体部门）去实现
		 * 
		 * @param ge
		 */
		public abstract void visit(GeneralEmployee ge);

	}

	/**
	 * 具体访问者对象：公司财务部<br/>
	 * 财务部的职责就是负责统计核算员工的工资
	 *
	 */
	public static class FADepartment extends Department {

		/**
		 * 访问公司管理者对象的每月工资
		 */
		@Override
		public void visit(ManagerEmployee me) {
			double totalWage = me.getTotalWage();
			System.out.println("管理者: " + me.getName() + "  固定工资 =" + me.getWage() + ", 迟到时长 " + me.getPunishmentTime()
					+ "小时" + ", 实发工资=" + totalWage);
		}

		/**
		 * 访问公司普通员工对象的每月工资
		 */
		@Override
		public void visit(GeneralEmployee ge) {
			double totalWage = ge.getTotalWage();
			System.out.println("普通员工: " + ge.getName() + "  固定工资 =" + ge.getWage() + ", 迟到时长 " + ge.getPunishmentTime()
					+ "小时" + ", 实发工资=" + totalWage);
		}
	}

	/**
	 * 具体访问者对象：公司人力资源部<br/>
	 * 人力资源部的职责就是负责统计核算员工的每月上班时长
	 * 
	 * @author lvzb.software@qq.com
	 *
	 */
//	public class HRDepartment extends Department {
//
//		/**
//		 * 访问公司管理者对象的每月实际上班时长统计
//		 */
//		@Override
//		public void visit(ManagerEmployee me) {
//			me.getTotalTimeSheet();
//		}
//
//		/**
//		 * 访问公司普通员工对象的每月实际上班时长统计
//		 */
//		@Override
//		public void visit(GeneralEmployee ge) {
//			ge.getTotalTimeSheet();
//		}
//
//	}

	public static void main(String[] args) {
		List<Employee> employeeList = new ArrayList<Employee>();
		Employee mep1, mep2, gep1, gep2, gep3;
		// 管理者1
		mep1 = new ManagerEmployee("王总", 8, 20000, 10);
		// 管理者2
		mep2 = new ManagerEmployee("谢经理", 8, 15000, 15);
		// 普通员工1
		gep1 = new GeneralEmployee("小杰", 8, 8000, 8);
		// 普通员工2
		gep2 = new GeneralEmployee("小晓", 8, 8500, 12);
		// 普通员工3
		gep3 = new GeneralEmployee("小虎", 8, 7500, 0);

		employeeList.add(mep1);
		employeeList.add(mep2);
		employeeList.add(gep1);
		employeeList.add(gep2);
		employeeList.add(gep3);

		// 财务部 对公司员工的工资核算/访问
		FADepartment department = new FADepartment();
		for (Employee employee : employeeList) {
			employee.accept(department);
		}
	}
}
